home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 September / LiquidLibrary 2005 Sep - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / gs_setpd.ps < prev    next >
Text File  |  2003-01-03  |  25KB  |  758 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile$ $Revision$
  6. % The current implementation of setpagedevice has the following limitations:
  7. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  8.  
  9. languagelevel 1 .setlanguagelevel
  10. level2dict begin
  11.  
  12. % ---------------- Redefinitions ---------------- %
  13.  
  14. % Redefine .beginpage and .endpage so that they call BeginPage and
  15. % EndPage respectively if appropriate.
  16.  
  17. % We have to guard against the BeginPage procedure not popping its operand.
  18. % This is really stupid, but the Genoa CET does it.
  19. /.beginpage {        % - .beginpage -
  20.   .currentshowpagecount {
  21.     .currentpagedevice pop
  22.     dup null ne { /BeginPage .knownget } { pop false } ifelse {
  23.         % Stack: ... pagecount proc
  24.        count 2 .execn
  25.         % Stack: ... ..???.. oldcount
  26.        count 1 add exch sub { pop } repeat
  27.     } {
  28.       pop
  29.     } ifelse
  30.   } if
  31. } bind odef
  32.  
  33. % Guard similarly against EndPage not popping its operand.
  34. /.endpage {        % <reason> .endpage <print_bool>
  35.   .currentshowpagecount {
  36.     1 index .currentpagedevice pop
  37.     dup null ne { /EndPage .knownget } { pop false } ifelse {
  38.         % Stack: ... reason pagecount reason proc
  39.       count 2 .execn
  40.         % Stack: ... ..???.. print oldcount
  41.       count 2 add exch sub { exch pop } repeat
  42.     } {
  43.       pop pop 2 ne
  44.     } ifelse
  45.   } {
  46.     2 ne
  47.   } ifelse
  48. } bind odef
  49.  
  50. % Define interpreter callouts for handling gstate-saving operators,
  51. % to make sure that they create a page device dictionary for use by
  52. % the corresponding gstate-restoring operator.
  53. % We'd really like to avoid the cost of doing this, but we don't see how.
  54. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  55. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  56. % interpreter.
  57.  
  58. (%gsavepagedevice) cvn
  59.  { currentpagedevice pop gsave
  60.  } bind def
  61.  
  62. (%savepagedevice) cvn
  63.  { currentpagedevice pop save
  64.  } bind def
  65.  
  66. (%gstatepagedevice) cvn
  67.  { currentpagedevice pop gstate
  68.  } bind def
  69.  
  70. (%copygstatepagedevice) cvn
  71.  { currentpagedevice pop copy
  72.  } bind def
  73.  
  74. (%currentgstatepagedevice) cvn
  75.  { currentpagedevice pop currentgstate
  76.  } bind def
  77.  
  78. % Define interpreter callouts for handling gstate-restoring operators
  79. % when the current page device needs to be changed.
  80. % The names %grestorepagedevice, %grestoreallpagedevice,
  81. % %restorepagedevice, %restore1pagedevice, and %setgstatepagedevice
  82. % are known to the interpreter.
  83.  
  84. /.installpagedevice
  85.  {    % Since setpagedevice doesn't create new device objects,
  86.     % we must (carefully) reinstall the old parameters in
  87.     % the same device.
  88.    .currentpagedevice pop null currentdevice null .trysetparams
  89.    dup type /booleantype eq
  90.     { pop pop }
  91.     {        % This should never happen!
  92.       DEBUG { (Error in .trysetparams!) = pstack flush } if
  93.       cleartomark pop pop pop
  94.       /.installpagedevice cvx /rangecheck signalerror
  95.     }
  96.    ifelse pop pop
  97.     % A careful reading of the Red Book reveals that an erasepage
  98.     % should occur, but *not* an initgraphics.
  99.    erasepage .beginpage
  100.  } bind def
  101.  
  102. /.uninstallpagedevice
  103.  { 2 .endpage { .currentnumcopies false .outputpage } if
  104.    nulldevice
  105.  } bind def
  106.  
  107. (%grestorepagedevice) cvn
  108.  { .uninstallpagedevice grestore .installpagedevice
  109.  } bind def
  110.  
  111. (%grestoreallpagedevice) cvn
  112.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  113.  } bind def
  114.  
  115. (%restore1pagedevice) cvn
  116.  { .uninstallpagedevice grestore .installpagedevice restore
  117.  } bind def
  118.  
  119. (%restorepagedevice) cvn
  120.  { .uninstallpagedevice restore .installpagedevice
  121.  } bind def
  122.  
  123. (%setgstatepagedevice) cvn
  124.  { .uninstallpagedevice setgstate .installpagedevice
  125.  } bind def
  126.  
  127. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  128. /.numcopiesdict mark
  129.   /NumCopies dup
  130. .dicttomark readonly def
  131.  
  132. /.currentnumcopies
  133.  { currentdevice //.numcopiesdict .getdeviceparams
  134.    dup type /integertype eq
  135.     { exch pop exch pop }
  136.     { cleartomark #copies }
  137.    ifelse
  138.  } bind odef
  139.  
  140. % Redefine .currentpagedevice and .setpagedevice so they convert between
  141. % null and a fixed empty directionary.
  142. /.nullpagedevice 0 dict readonly def
  143. /.currentpagedevice {
  144.   //.currentpagedevice exch dup null eq { pop //.nullpagedevice } if exch
  145. } bind odef
  146. /.setpagedevice {
  147.   dup //.nullpagedevice eq { pop null } if //.setpagedevice
  148. } bind odef
  149.  
  150. % ---------------- Auxiliary definitions ---------------- %
  151.  
  152. % Define the required attributes of all page devices, and their default values.
  153. % We don't include attributes such as .MediaSize, which all devices
  154. % are guaranteed to supply on their own.
  155. /.defaultpolicies mark
  156.   /PolicyNotFound 1
  157.   /PageSize 0
  158.   /PolicyReport {pop} bind
  159. .dicttomark readonly def
  160. % Note that the values of .requiredattrs are executed, not just fetched.
  161. /.requiredattrs mark
  162.   /PageDeviceName null
  163.   /PageOffset [0 0] readonly
  164. % We define InputAttributes and OutputAttributes with a single
  165. % dummy media type that handles pages of any size.
  166. % Devices that care will override this.
  167.   /InputAttributes {
  168.     mark 0
  169.     % Since sizes match within 5 user units, we need to set the smallest
  170.     % PageSize to 6 units so that [0 0] will fail.
  171.     mark /PageSize [6 dup 16#7ffff dup] .dicttomark
  172.     .dicttomark
  173.   }
  174.   (%MediaSource) 0
  175.   /OutputAttributes {
  176.     mark 0 mark .dicttomark readonly .dicttomark
  177.   }
  178.   (%MediaDestination) 0
  179.   /Install {{.callinstall}} bind
  180.   /BeginPage {{.callbeginpage}} bind
  181.   /EndPage {{.callendpage}} bind
  182.   /Policies .defaultpolicies
  183. .dicttomark readonly def
  184.  
  185. % Define currentpagedevice so it creates the dictionary on demand if needed,
  186. % adding all the required entries defined just above.
  187. % We have to deal specially with entries that the driver may change
  188. % on its own.
  189. /.dynamicppkeys mark
  190.   /.MediaSize dup        % because it changes when PageSize is set
  191.   /PageCount dup
  192. .dicttomark readonly def
  193. /.makecurrentpagedevice {    % - .makecurrentpagedevice <dict>
  194.   currentdevice null .getdeviceparams
  195.     % Make the dictionary large enough to add defaulted entries.
  196.   counttomark 2 idiv .requiredattrs length add dict
  197.   counttomark 2 idiv { dup 4 2 roll put } repeat exch pop
  198.     % Add any missing required attributes.
  199.     % Make a writable and (if possible) local copy of any default
  200.     % dictionaries, to work around a bug in the output of WordPerfect,
  201.     % which assumes that these dictionaries are writable and local.
  202.   .currentglobal exch dup gcheck .setglobal
  203.   .requiredattrs {
  204.     2 index 2 index known {
  205.       pop pop
  206.     } {
  207.       exec 2 index 3 1 roll put
  208.     } ifelse
  209.   } forall exch .setglobal
  210.   dup .setpagedevice
  211. } bind def
  212. /currentpagedevice {
  213.   .currentpagedevice {
  214.     dup length 0 eq {
  215.       pop .makecurrentpagedevice
  216.     } {
  217.         % If any of the dynamic keys have changed,
  218.         % we must update the page device dictionary.
  219.       currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {
  220.         % Stack: current key value
  221.         2 index 2 index .knownget { 1 index ne } { true } ifelse
  222.          { 2 index wcheck not
  223.         {    % This is the first entry being updated.
  224.             % Copy the dictionary to make it writable.
  225.           3 -1 roll dup length dict .copydict
  226.           3 1 roll
  227.         }
  228.            if
  229.            2 index 3 1 roll put
  230.          }
  231.          { pop pop
  232.          }
  233.         ifelse
  234.       } forall
  235.         % If the dictionary was global and is now local, copy
  236.         % any global subsidiary dictionaries to local VM.  This
  237.         % too is to work around the Word Perfect bug (see above).
  238.       dup gcheck not {
  239.     dup {
  240.       dup type /dicttype eq { dup gcheck } { false } ifelse {
  241.         % Copy-on-write, see above.
  242.         2 index wcheck not {
  243.           3 -1 roll dup length dict .copydict
  244.           3 1 roll
  245.         } if
  246.         .copytree 2 index 3 1 roll put
  247.       } {
  248.         pop pop
  249.       } ifelse
  250.     } forall
  251.       } if
  252.         % We would like to do a .setpagedevice so we don't keep
  253.         % re-creating the dictionary.  Unfortunately, the effect
  254.         % of this is that if any dynamic key changes (PageCount
  255.         % in particular), we will do the equivalent of a
  256.         % setpagedevice at the next restore or grestore.
  257.         % Therefore, we make the dictionary read-only, but
  258.         % we don't store it away.  I.e., NOT:
  259.         % dup wcheck { .setpagedevice .currentpagedevice pop } if
  260.       readonly
  261.     } ifelse
  262.   } if
  263. } bind odef
  264.  
  265. % Copy a dictionary recursively.
  266. /.copytree {    % <dict> .copytree <dict'>
  267.   dup length dict exch {
  268.     dup type /dicttype eq { .copytree } if 2 index 3 1 roll put
  269.   } forall
  270. } bind def
  271.  
  272. % The implementation of setpagedevice is quite complex.  Currently,
  273. % everything but the media matching algorithm is implemented here.
  274.  
  275. % By default, we only present the requested changes to the device,
  276. % but there are some parameters that require special merging action.
  277. % Define those parameters here, with the procedures that do the merging.
  278. % The procedures are called as follows:
  279. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  280. /.mergespecial mark
  281.   /InputAttributes
  282.    { dup null eq
  283.       { pop null
  284.       }
  285.       { 3 copy pop .knownget
  286.      { dup null eq
  287.         { pop dup length dict }
  288.         { dup length 2 index length add dict .copydict }
  289.        ifelse
  290.      }
  291.      { dup length dict
  292.      }
  293.         ifelse .copydict readonly
  294.       }
  295.      ifelse
  296.    } bind
  297.   /OutputAttributes 1 index
  298.   /Policies
  299.     { 3 copy pop .knownget
  300.        { dup length 2 index length add dict .copydict }
  301.        { dup length dict }
  302.       ifelse copy readonly
  303.     } bind
  304. .dicttomark readonly def
  305.  
  306. % Define the keys used in input attribute matching.
  307. /.inputattrkeys [
  308.   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  309.     % The following are documented in Adobe's supplement for v2017.
  310.   /LeadingEdge /MediaClass
  311. ] readonly def
  312. % Define other keys used in media selection.
  313. /.inputselectionkeys [
  314.   /MediaPosition /Orientation
  315. ] readonly def
  316.  
  317. % Define the keys used in output attribute matching.
  318. /.outputattrkeys [
  319.   /OutputType
  320. ] readonly def
  321.  
  322. % Define all the parameters that should always be copied to the merged
  323. % dictionary.
  324. /.copiedkeys [
  325.   /OutputDevice
  326.   .mergespecial { pop } forall
  327.   .inputattrkeys aload pop
  328.   .inputselectionkeys aload pop
  329.   .outputattrkeys aload pop
  330. ] readonly def
  331.  
  332. % Define the parameters that should not be presented to the device.
  333. % The procedures are called as follows:
  334. %    <merged> <key> <value> -proc-
  335. % The procedure leaves all its operands on the stack and returns
  336. % true iff the key/value pair should be presented to .putdeviceparams.
  337. /.presentspecial mark
  338.   .dynamicppkeys { pop false } forall
  339.             % We must ignore an explicit request for .MediaSize,
  340.             % because media matching always handles this.
  341.   /.MediaSize false
  342.   /Name false
  343.   /OutputDevice false
  344.   /PageDeviceName false
  345.   /PageOffset false
  346.   /PageSize false        % obsolete alias for .MediaSize
  347.   /InputAttributes false
  348.   .inputattrkeys
  349.     { dup /PageSize eq
  350.        { pop }
  351.        { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  352.       ifelse
  353.     }
  354.   forall
  355.   .inputselectionkeys { false } forall
  356.   /OutputAttributes false
  357.   .outputattrkeys
  358.     { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  359.   forall
  360.   /Install false
  361.   /BeginPage false
  362.   /EndPage false
  363.   /Policies false
  364.     % Our extensions:
  365.   /HWColorMap
  366.     {            % HACK: don't transmit the color map, because
  367.             % window systems can change the color map on their own
  368.             % incrementally.  Someday we'll have a better
  369.             % solution for this....
  370.       false
  371.     }
  372.   /ViewerPreProcess false
  373. .dicttomark readonly def
  374.  
  375. % Define access to device defaults.
  376. /.defaultdeviceparams
  377.  { finddevice null .getdeviceparams
  378.  } bind def
  379.  
  380. % Select media (input or output).  The hard work is done in an operator:
  381. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  382. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  383. %    <pagedict> null <policydict> <keys> .matchmedia null true
  384. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  385.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  386.             %   .selectmedia
  387.  { 5 index 5 -2 roll 4 index .matchmedia
  388.         % Stack: orig request merged failed attrkeys mediakey
  389.         %   (key true | false)
  390.     { 4 index 3 1 roll put pop
  391.     }
  392.     {    % Adobe's implementations have a "big hairy heuristic"
  393.     % to choose the set of keys to report as having failed the match.
  394.     % For the moment, we report any keys that are in the request
  395.     % and don't have the same value as in the original dictionary.
  396.       5 index 1 index .knownget
  397.        { 4 index 3 1 roll put }
  398.        { 3 index exch .undef }
  399.       ifelse
  400.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  401.      3 index 1 index .knownget
  402.       { 5 index 2 index .knownget { ne } { pop true } ifelse }
  403.       { true }
  404.      ifelse        % Stack: ... <failed> <attrkey> <report>
  405.       { 2 copy /rangecheck put }
  406.      if pop
  407.        }
  408.       forall
  409.     }
  410.    ifelse
  411.  } bind def
  412.  
  413. % Apply Policies to any unprocessed failed requests.
  414. % As we process each request entry, we replace the error name
  415. % in the <failed> dictionary with the policy value,
  416. % and we replace the key in the <merged> dictionary with its prior value
  417. % (or remove it if it had no prior value).
  418. /.policyprocs mark
  419. % These procedures are called with the following on the stack:
  420. %   <orig> <merged> <failed> <Policies> <key> <policy>
  421. % They are expected to consume the top 2 operands.
  422. % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
  423. % the same as 0, i.e., we signal an error.
  424.   0 {        % Set errorinfo and signal a configurationerror.
  425.     pop dup 4 index exch get 2 array astore
  426.     $error /errorinfo 3 -1 roll put
  427.     cleartomark
  428.     /setpagedevice load /configurationerror signalerror
  429.   } bind
  430.   1 {        % Roll back the failed request to its previous status.
  431. DEBUG { (Rolling back.) = pstack flush } if
  432.     3 index 2 index 3 -1 roll put
  433.     4 index 1 index .knownget
  434.      { 4 index 3 1 roll put }
  435.      { 3 index exch .undef }
  436.     ifelse
  437.   } bind
  438.   7 {        % For PageSize only, just impose the request.
  439.     1 index /PageSize eq
  440.      { pop pop 1 index /PageSize 7 put }
  441.      { .policyprocs 0 get exec }
  442.     ifelse
  443.   } bind
  444. .dicttomark readonly def
  445. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  446.             %   <orig> <merged'> <failed'>
  447.  { 1 index /Policies get 1 index
  448.     { type /integertype eq
  449.        { pop        % already processed
  450.        }
  451.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  452.             % Stack: <orig> <merged> <failed> <Policies> <key>
  453.             %   <policy>
  454.      .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
  455.        }
  456.       ifelse
  457.     }
  458.    forall pop
  459.  } bind def
  460.  
  461. % Prepare to present parameters to the device, by spreading them onto the
  462. % operand stack and removing any that shouldn't be presented.
  463. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  464.  { mark exch dup
  465.     {            % Stack: -mark- key1 value1 ... merged key value
  466.       .presentspecial 2 index .knownget
  467.        { exec { 3 -1 roll } { pop pop } ifelse }
  468.        { 3 -1 roll }
  469.       ifelse
  470.     }
  471.    forall pop
  472.  } bind def
  473.  
  474. % Put device parameters without resetting currentpagedevice.
  475. % (.putdeviceparams clears the current page device.)
  476. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  477.             %   <key1> <value1> ... .putdeviceparamsonly
  478.             % On success: <device> <eraseflag>
  479.             % On failure: <device> <Policies|null> <req_all> -mark-
  480.             %   <key1> <error1> ...
  481.  { .currentpagedevice
  482.     { counttomark 4 add 1 roll .putdeviceparams
  483.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  484.       .setpagedevice
  485.     }
  486.     { pop .putdeviceparams
  487.     }
  488.    ifelse
  489.  } bind def
  490.  
  491. % Try setting the device parameters from the merged request.
  492. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  493.             %   .trysetparams
  494.  { true 4 index .prepareparams
  495.             % Add the computed .MediaSize.
  496.             % Stack: merged (ignored) device Policies -true-
  497.             %   -mark- key1 value1 ...
  498.    counttomark 5 add index .computemediasize
  499.    exch pop exch pop /.MediaSize exch
  500. DEBUG { (Putting.) = pstack flush } if
  501.    .putdeviceparamsonly
  502. DEBUG { (Result of putting.) = pstack flush } if
  503.  } bind def
  504.  
  505. % Compute the media size and initial matrix from a merged request (after
  506. % media selection).
  507. /.computemediasize    % <request> .computemediasize
  508.             %   <request> <matrix> <[width height]>
  509.  { dup /PageSize get                    % requested page size
  510.    1 index /InputAttributes get
  511.      2 index (%MediaSource) get get /PageSize get    % media size
  512.                             % (may be a range)
  513.    2 index /Policies get
  514.      dup /PageSize .knownget
  515.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  516.                             % affects scaling
  517.    3 index /Orientation .knownget not { null } if
  518.    4 index /RollFedMedia .knownget not { false } if
  519.    matrix .matchpagesize not {
  520.         % This is a "can't happen" condition!
  521.      /setpagedevice load /rangecheck signalerror
  522.    } if
  523.    2 array astore
  524.  } bind def
  525.  
  526. % ---------------- setpagedevice itself ---------------- %
  527.  
  528. /setpagedevice
  529.  {        % We mustn't pop the argument until the very end,
  530.         % so that the pseudo-operator machinery can restore the stack
  531.         % if an error occurs.
  532.    mark 1 index currentpagedevice
  533.  
  534.         % Check whether we are changing OutputDevice;
  535.         % also handle the case where the current device
  536.         % is not a page device.
  537.         % Stack: mark <request> <current>
  538. DEBUG { (Checking.) = pstack flush } if
  539.  
  540.    dup /OutputDevice .knownget
  541.     {        % Current device is a page device.
  542.       2 index /OutputDevice .knownget
  543.        {    % A specific OutputDevice was requested.
  544.      2 copy eq
  545.       { pop pop null }
  546.       { exch pop }
  547.      ifelse
  548.        }
  549.        { pop null
  550.        }
  551.       ifelse
  552.     }
  553.     {        % Current device is not a page device.
  554.         % Use the default device.
  555.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  556.     }
  557.    ifelse
  558.    dup null eq
  559.     { pop
  560.     }
  561.     { exch pop .defaultdeviceparams
  562.         % In case of duplicate keys, .dicttomark takes the entry
  563.         % lower on the stack, so we can just append the defaults here.
  564.       .requiredattrs { exec } forall .dicttomark
  565.     }
  566.    ifelse
  567.  
  568.         % Check whether a viewer wants to intervene.
  569.         % We must check both the request (which takes precedence)
  570.         % and the current dictionary.
  571.         % Stack: mark <request> <orig>
  572.    exch dup /ViewerPreProcess .knownget
  573.     { exec }
  574.     { 1 index /ViewerPreProcess .knownget { exec } if }
  575.    ifelse exch
  576.  
  577.         % Construct a merged request from the actual request plus
  578.         % any keys that should always be propagated.
  579.         % Stack: mark <request> <orig>
  580. DEBUG { (Merging.) = pstack flush } if
  581.  
  582.    exch 1 index length 1 index length add dict
  583.    .copiedkeys
  584.     {        % Stack: <orig> <request> <merged> <key>
  585.       3 index 1 index .knownget { 3 copy put pop } if pop
  586.     }
  587.    forall
  588.         % Stack: <orig> <request> <merged>
  589.    dup 2 index
  590.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  591.       .mergespecial 2 index .knownget { exec } if
  592.       put dup
  593.     }
  594.    forall pop
  595.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  596.         % change HWResolution.
  597.    FIXEDRESOLUTION { dup /HWResolution .undef } if
  598.         % Hack: if FIXEDMEDIA is true, discard any attempt to change
  599.         % PageSize or HWSize.
  600.    FIXEDMEDIA
  601.     { dup /PageSize 4 index /PageSize get put
  602.       dup /HWSize 4 index /HWSize get put
  603.     } if
  604.         % Hack: to work around some files that take a PageSize
  605.         % from InputAttributes and impose it, discard any attempt
  606.         % to set PageSize to a 4-element value.
  607.         % Stack: mark <orig> <request> <merged>
  608.     dup /PageSize .knownget {
  609.       length 2 ne {
  610.     dup /PageSize 4 index /PageSize get put
  611.       } if
  612.     } if
  613.  
  614.         % Select input and output media.
  615.         % Stack: mark <orig> <request> <merged>
  616. DEBUG { (Selecting.) = pstack flush } if
  617.  
  618.    0 dict    % <failed>
  619.    1 index /InputAttributes .knownget
  620.     { 2 index /Policies get
  621.       .inputattrkeys (%MediaSource) cvn .selectmedia
  622.     } if
  623.    1 index /OutputAttributes .knownget
  624.     { 2 index /Policies get
  625.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  626.      } if
  627.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  628.    .applypolicies
  629.    3 -1 roll 4 1 roll        % swap back
  630.  
  631.         % Construct the new device, and attempt to set its attributes.
  632.         % Stack: mark <orig> <request> <merged> <failed>
  633. DEBUG { (Constructing.) = pstack flush } if
  634.  
  635.    currentdevice .devicename 2 index /OutputDevice get eq
  636.     { currentdevice }
  637.     { 1 index /OutputDevice get finddevice }
  638.    ifelse
  639.         %**************** We should copy the device here,
  640.         %**************** but since we can't close the old device,
  641.         %**************** we don't.  This is WRONG.
  642.     %****************copydevice
  643.    2 index /Policies get
  644.    .trysetparams
  645.    dup type /booleantype ne
  646.     {        % The request failed.
  647.         % Stack: ... <orig> <request> <merged> <failed> <device>
  648.         %   <Policies> true mark <name> <errorname> ...
  649. DEBUG { (Recovering.) = pstack flush } if
  650.       counttomark 4 add index
  651.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  652.       pop pop pop
  653.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  654.         %   <Policies>
  655.       6 2 roll 3 -1 roll 4 1 roll
  656.       .applypolicies
  657.       3 -1 roll 4 1 roll 6 -2 roll
  658.       .trysetparams        % shouldn't fail!
  659.       dup type /booleantype ne
  660.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  661.          /setpagedevice load exch signalerror
  662.        }
  663.       if
  664.     }
  665.    if
  666.  
  667.         % The attempt succeeded.  Install the new device.
  668.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  669. DEBUG { (Installing.) = pstack flush } if
  670.  
  671.    pop 2 .endpage
  672.     { 1 true .outputpage
  673.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  674.     }
  675.    if
  676.         % .setdevice clears the current page device!
  677.    .currentpagedevice pop exch
  678.    .setdevice pop
  679.    .setpagedevice
  680.  
  681.         % Merge the request into the current page device,
  682.         % unless we're changing the OutputDevice.
  683.         % Stack: mark ... <merged> <failed>
  684.    exch currentpagedevice dup length 2 index length add dict
  685.         % Stack: mark ... <failed> <merged> <current> <newdict>
  686.    2 index /OutputDevice .knownget {
  687.      2 index /OutputDevice .knownget not { null } if eq
  688.    } {
  689.      true
  690.    } ifelse {
  691.         % Same OutputDevice, merge the dictionaries.
  692.      .copydict
  693.    } {
  694.         % Different OutputDevice, discard the old dictionary.
  695.      exch pop
  696.    } ifelse .copydict
  697.         % Initialize the default matrix, taking media matching
  698.         % into account.
  699.    .computemediasize pop initmatrix concat
  700.    dup /PageOffset .knownget
  701.     {        % Translate by the given number of 1/72" units in device X/Y.
  702.       dup 0 get exch 1 get
  703.       2 index /HWResolution get dup 1 get exch 0 get
  704.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  705.       idtransform translate
  706.     }
  707.    if
  708.         % We must install the new page device dictionary
  709.         % before calling the Install procedure.
  710.   dup .setpagedevice
  711.   .setdefaultscreen    % Set the default screen before calling Install.
  712.   dup /Install .knownget {
  713.     { .execinstall } stopped { .postinstall stop } { .postinstall } ifelse
  714.   } {
  715.     .postinstall
  716.   } ifelse
  717. } odef
  718.  
  719. % We break out the code after calling the Install procedure into a
  720. % separate procedure, since it is executed even if Install causes an error.
  721. % By making .execinstall a separate operator procedure, we get the stacks
  722. % restored if it fails.
  723.  
  724. /.execinstall {        % <proc> .execinstall -
  725.     % Because the interpreter optimizes tail calls, we can't just let
  726.     % the body of this procedure be 'exec', because that would lose
  727.     % the stack protection that is the whole reason for having the
  728.     % procedure in the first place.  We hack this by adding a couple
  729.     % of extra tokens to ensure that the operator procedure is still
  730.     % on the stack during the exec.
  731.   exec
  732.   0 pop    % See above.
  733. } odef
  734. /.postinstall {        % mark ... <failed> <merged> .postinstall -
  735.    matrix currentmatrix .setdefaultmatrix
  736.         % Erase and initialize the page.
  737.    erasepage initgraphics
  738.    .beginpage
  739.  
  740.         % Clean up, calling PolicyReport if needed.
  741.         % Stack: mark ... <failed> <merged>
  742. DEBUG { (Finishing.) = pstack flush } if
  743.  
  744.    exch dup length 0 ne
  745.     { 1 index /Policies get /PolicyReport get
  746.       counttomark 1 add 2 roll cleartomark
  747.       exec
  748.     }
  749.     { cleartomark
  750.     }
  751.    ifelse pop
  752.  
  753. } odef
  754.  
  755. end                % level2dict
  756. .setlanguagelevel
  757.